﻿#include "monsterrole.h"
#include "mapmanager.h"
#include "common.h"

#include <QLineF>
#include <QDateTime>
#include <QRandomGenerator>

MonsterRole::MonsterRole()
    : BaseRole(ROLETYPE_MONSTER),
      mGuardDistance(0),
      mAttackDistance(0),
      mGuardPlayer(NULL),
      mGuardPlayerTime(0),
      mCurAcitivityMapId(-1),
      mCurMapActivityRectId(-1),
      mCurAttackTime(0),
      mAttackTimeSpace(0),
      mCurStateTime(0)
{

}

MonsterRole::~MonsterRole()
{

}

/**
 * @brief MonsterRole::reset 重置
 */
void MonsterRole::reset(void)
{
    setState(ROLESTATE_WAITING);
    //setActivityRect(getActivityRect());

    if(isExistActivityMap(getCurAcitivityMapId()))
    {
        int tmpactivityrectcount = mActivityMaps[getCurAcitivityMapId()].size();
        mCurMapActivityRectId = qrand()%tmpactivityrectcount;
        QRect tmpActivityRect = mActivityMaps[getCurAcitivityMapId()][mCurMapActivityRectId];

        setPosition(QPoint(tmpActivityRect.left()+qrand()%tmpActivityRect.width(),
                           tmpActivityRect.top()+qrand()%tmpActivityRect.height()));
    }

    setAngle(qrand()%360);

    if(this->isAngleChanged() || this->isPosChanged())
        this->setStateChanged(true);
}

/**
 * @brief MonsterRole::getActivityMap 得到活动地图
 * @param mapid
 * @return
 */
inline QList<QRect> MonsterRole::getActivityMap(int mapid)
{
    QHash<int,QList<QRect>>::iterator iter = mActivityMaps.find(mapid);
    if(iter != mActivityMaps.end())
        return iter.value();

    return QList<QRect>();
}

/**
 * @brief MonsterRole::addActivityMap 添加活动地图
 * @param mapid
 * @param rect
 * @return
 */
bool MonsterRole::addActivityMap(int mapid,QRect rect)
{
    mActivityMaps[mapid].push_back(rect);

    return true;
}

/**
 * @brief MonsterRole::isExistActivityMap 检测指定的地图编码是否属于当前活动地图
 * @param map
 * @return
 */
bool MonsterRole::isExistActivityMap(int mapid)
{
    QHash<int,QList<QRect>>::iterator iter = mActivityMaps.find(mapid);
    if(iter != mActivityMaps.end())
        return true;

    return false;
}

/**
 * @brief MonsterRole::getGuardDistancePlayers 得到警戒距离内的玩家
 * @return
 */
QList<BaseRole*> MonsterRole::getGuardDistancePlayers(void)
{
    QList<BaseRole*> guardPlayers;

    QList<BaseRole*> viewPlayers = getViewRoleList(ROLETYPE_PLAYER);
    QList<BaseRole*>::iterator iter = viewPlayers.begin();
    for(;iter != viewPlayers.end();++iter)
    {
        double tmpDistance = calculateDistanceOptimized(this->getPosition(),(*iter)->getPosition());
        if((*iter) == this || tmpDistance > getGuardDistance())
            continue;

        guardPlayers.push_back((*iter));
    }

    return guardPlayers;
}

/**
 * @brief MonsterRole::Attack 发动一次攻击
 */
void MonsterRole::Attack(BaseRole *pBaseRole)
{
    if(pBaseRole == NULL ||
       pBaseRole->getRoleType() != ROLETYPE_PLAYER) return;

    QVector<int> tmpbullets = this->getUsingBullets();
    int decbullet = tmpbullets[qrand()%tmpbullets.size()];

    QJsonObject returnObj;
    returnObj["msgtype"] = IDD_NETWORK_ATTACK;

    QJsonObject bulletObj;
    bulletObj["bullet"] = decbullet;
    bulletObj["attackid"] = this->getID();
    bulletObj["startx"] = this->getPosition().x();
    bulletObj["starty"] = this->getPosition().y();
    bulletObj["angle"] = 360-QLineF(this->getPosition(),getGuardPlayer()->getPosition()).angle();

    returnObj["content"] = bulletObj;

    MapManager::getSingleton().sendViewRoles(pBaseRole,JsonToString(returnObj));
}

/**
 * @brief MonsterRole::onProcessAttack 攻击处理
 */
void MonsterRole::onProcessAttack(void)
{
    if(this->getState() == ROLESTATE_GUARD || this->getState() == ROLESTATE_PURSURE)
    {
        // 判断被警戒的NPC和玩家距离是否达到攻击距离
        double distance = calculateDistanceOptimized(this->getPosition(),getGuardPlayer()->getPosition());
        if(distance < this->getAttackDistance())
        {
            // 如果达到攻击距离开始攻击
            this->setState(ROLESTATE_ATTACK);

            mCurAttackTime = QDateTime::currentMSecsSinceEpoch();
        }
    }
    else if(this->getState() == ROLESTATE_ATTACK)
    {
        double tmpAngle = 360-QLineF(this->getPosition(),getGuardPlayer()->getPosition()).angle();
        this->setAngle(tmpAngle);

        if(this->isAngleChanged() || this->isPosChanged())
            this->setStateChanged(true);

        double distance = calculateDistanceOptimized(this->getPosition(),getGuardPlayer()->getPosition());
        if(distance < this->getGuardDistance() && distance > this->getAttackDistance())
        {
            this->setState(ROLESTATE_GUARD);
            this->mCurStateMaxTime=(QRandomGenerator::global()->bounded(2000)+1000);
            this->setStateStartTime(QDateTime::currentMSecsSinceEpoch());
        }
        else
        {
            // 检查血量是否太小，太小就逃跑
            if(this->getBlood() < this->getsrcBlood()/2 &&
               QRandomGenerator::global()->bounded(100) < this->getEscaperate())
            {
                mWalkingMaxTime = QRandomGenerator::global()->bounded(100)+100;
                mWaokingAngle = (float)(((int)this->getAngle() + 180) % 360);

                this->setState(ROLESTATE_ESCAPE);
            }
            else
            {
                if(QDateTime::currentMSecsSinceEpoch() > mCurAttackTime + mAttackTimeSpace)
                {
                    Attack(getGuardPlayer());

                    mCurAttackTime = QDateTime::currentMSecsSinceEpoch();
                }
            }
        }
    }
}

/**
 * @brief MonsterRole::onProcessGuard 警戒处理
 */
void MonsterRole::onProcessGuard(void)
{
    if(this->getState() == ROLESTATE_ATTACK || this->getState() == ROLESTATE_PURSURE)
        return;

    if(this->getState() == ROLESTATE_GUARD)
    {
        // 如果警戒时间过长，如果血量是被攻击者的两倍就攻击，否则就朝反方向移动
        if(QDateTime::currentMSecsSinceEpoch() >
                this->getStateStartTime() + this->mCurStateMaxTime)
        {
            mWalkingMaxTime = QRandomGenerator::global()->bounded(100)+100;
            mWaokingAngle = (float)(((int)this->getAngle() + 180) % 360);

            this->setState(ROLESTATE_WALKING);

            if(this->getBlood() > this->getGuardPlayer()->getBlood())
            {
                mWaokingAngle = (int)this->getAngle();
                this->setState(ROLESTATE_PURSURE);
            }

            return;
        }

        BaseRole *lastDistanceRole = NULL;
        QList<BaseRole*> guardPlayers = getGuardDistancePlayers();
        if(!guardPlayers.isEmpty())
        {
            int lastDistance = getGuardDistance();

            // 找到距离最近的
            for(int i=0;i<guardPlayers.size();i++)
            {
                double distance = calculateDistanceOptimized(this->getPosition(),guardPlayers[i]->getPosition());
                if(distance <= lastDistance)
                {
                    lastDistance = distance;
                    lastDistanceRole = guardPlayers[i];
                }
            }
        }

        if(lastDistanceRole != NULL && lastDistanceRole != getGuardPlayer())
            this->setGuardPlayer(lastDistanceRole);

        if(calculateDistanceOptimized(this->getPosition(),getGuardPlayer()->getPosition()) <= getGuardDistance())
        {
            double tmpAngle = 360-QLineF(this->getPosition(),getGuardPlayer()->getPosition()).angle();
            this->setAngle(tmpAngle);

            if(this->isAngleChanged() || this->isPosChanged())
                this->setStateChanged(true);
           // MapManager::getSingleton().updateRoleMap(this);
        }
        else
        {
            QList<BaseRole*> guardPlayers = getGuardDistancePlayers();
            if(!guardPlayers.isEmpty())
            {
                mGuardPlayerTime = QDateTime::currentMSecsSinceEpoch();
                setGuardPlayer(guardPlayers[qrand()%guardPlayers.size()]);
            }
            else
            {
                setGuardPlayer(NULL);
                this->setState(ROLESTATE_WAITING);
            }
        }
    }
    else
    {
        // 检测当前是否需要警戒
        QList<BaseRole*> guardPlayers = getGuardDistancePlayers();
        if(!guardPlayers.isEmpty())
        {
            // 随机找到一个玩家
            BaseRole *pBaseRole = guardPlayers[qrand()%guardPlayers.size()];

            mGuardPlayerTime = QDateTime::currentMSecsSinceEpoch();
            this->setGuardPlayer(pBaseRole);
            this->setState(ROLESTATE_GUARD);
            this->setAngle(360-QLineF(this->getPosition(),pBaseRole->getPosition()).angle());

            this->mCurStateMaxTime=(QRandomGenerator::global()->bounded(2000)+1000);
            this->setStateStartTime(QDateTime::currentMSecsSinceEpoch());

            if(this->isAngleChanged() || this->isPosChanged())
                this->setStateChanged(true);
        }
    }
}

/**
 * @brief MonsterRole::update 更新
 */
void MonsterRole::update(void)
{
    if(getCurAcitivityMapId() < 0 || getCurMapActivityRectId() < 0) return;

    // 自动回血
    if(this->getBlood() < this->getsrcBlood())
    {
        this->mSelfhealingtotal+=this->getSelfHealing();

        if(this->mSelfhealingtotal >= 1.0f)
        {
            this->setBlood(this->getBlood()+(int)this->mSelfhealingtotal);
            this->mSelfhealingtotal=0.0f;

            //角色状态改变，要更新一下
            this->setStateChanged(true);
        }
    }

    // 逃跑具有最高处理权
    if(this->getState() == ROLESTATE_ESCAPE)
    {
        if(mWalkingMaxTime > 0)
        {
            mWalkingMaxTime--;
            QPoint tmppoint = calculateNewPoint(this->getPosition(),2,mWaokingAngle);
            if(!mActivityMaps[getCurAcitivityMapId()][getCurMapActivityRectId()].contains(tmppoint))
            {
                mWalkingMaxTime = 0;
                mWaokingAngle = 0.0f;
                this->setState(ROLESTATE_WAITING);
                return;
            }

            this->setAngle(mWaokingAngle);
            this->setPosition(tmppoint);

            if(this->isAngleChanged() || this->isPosChanged())
                this->setStateChanged(true);
        }
        else
        {
            mWalkingMaxTime = 0;
            mWaokingAngle = 0.0f;
            this->setState(ROLESTATE_WAITING);
        }

        MapManager::getSingleton().updateRoleMap(this);
        return;
    }

    // 警戒处理
    onProcessGuard();

    switch(this->getState())
    {
    case ROLESTATE_WAITING:          // 等待
    {
        if(this->getStateTime() > QRandomGenerator::global()->bounded(600000)+30000)
        {
            this->setState(ROLESTATE_WALKING);
        }
    }
        break;
    case ROLESTATE_PURSURE:          // 追击
    case ROLESTATE_WALKING:          // 行走
    {
        // 如果行走没有目标时间的话，初始一个时间
        if(mWalkingMaxTime == 0)
        {
            mWalkingMaxTime = QRandomGenerator::global()->bounded(200);
            mWaokingAngle = QRandomGenerator::global()->bounded(360);
        }
        else
        {
            if(mWalkingMaxTime > 0)
            {
                mWalkingMaxTime--;
                QPoint tmppoint = calculateNewPoint(this->getPosition(),2,mWaokingAngle);
                if(!mActivityMaps[getCurAcitivityMapId()][getCurMapActivityRectId()].contains(tmppoint))
                {
                    mWalkingMaxTime = 0;
                    mWaokingAngle = 0.0f;
                    this->setState(ROLESTATE_WAITING);
                    return;
                }

                this->setAngle(mWaokingAngle);
                this->setPosition(tmppoint);

                if(this->isAngleChanged() || this->isPosChanged())
                    this->setStateChanged(true);
            }
            else
            {
                mWalkingMaxTime = 0;
                mWaokingAngle = 0.0f;
                this->setState(ROLESTATE_WAITING);
            }
        }
    }
        break;
    default:
        break;
    }

    MapManager::getSingleton().updateRoleMap(this);

    // 攻击处理
    onProcessAttack();
}
